package com.ask.sms;

import com.ask.db.SqldbSMS;
import com.ask.resources.LoggerInf;
import com.ask.ui.JNotifWindow;
import com.ask.ui.TrayUI;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import org.smslib.*;
import org.smslib.AGateway.Protocols;
import org.smslib.InboundMessage.MessageClasses;
import org.smslib.Message.MessageTypes;
import org.smslib.helper.Logger;
import org.smslib.modem.SerialModemGateway;

public class serverku implements Runnable {

    private static String appPath = System.getProperty("user.dir");
    boolean shutdown = false;
    SqldbSMS dbsql;
    InboundNotification inboundNotification;
    OutboundNotification outboundNotification;
    CallNotification callNotification;
    QueueSendingNotification queueSendingNotification;
    OrphanedMessageNotification orphanedMessageNotification;
    InboundPollingThread inboundPollingThread;
    OutboundPollingThread outboundPollingThread;
    USSDboundNotification ussdboundNotification;
    //implicit
    private Thread thApp;

    public serverku() {
        Runtime.getRuntime().addShutdownHook(new Shutdown());
        this.dbsql = new SqldbSMS(this);
        this.inboundNotification = new InboundNotification();
        this.outboundNotification = new OutboundNotification();
        this.callNotification = new CallNotification();
        this.queueSendingNotification = new QueueSendingNotification();
        this.orphanedMessageNotification = new OrphanedMessageNotification();
        this.ussdboundNotification = new USSDboundNotification();
        this.inboundPollingThread = null;
        this.outboundPollingThread = null;
        Service.getInstance().setInboundMessageNotification(
                this.inboundNotification);
        Service.getInstance().setOutboundMessageNotification(
                this.outboundNotification);
        Service.getInstance().setCallNotification(this.callNotification);
        Service.getInstance().setQueueSendingNotification(
                this.queueSendingNotification);
        Service.getInstance().setOrphanedMessageNotification(
                this.orphanedMessageNotification);
        Service.getInstance().setUSSDNotification(this.ussdboundNotification);
        thApp = new Thread(this);
    }

    public void start() {
        thApp.start();
    }

    public boolean getShutdown() {
        return shutdown;
    }

    private void process() throws Exception {
//        this.inboundPollingThread = new InboundPollingThread();
//        this.inboundPollingThread.setName("SMSServer - InboundPollingThread");
//        this.inboundPollingThread.start();
        this.outboundPollingThread = new OutboundPollingThread();
        this.outboundPollingThread.setName("SMSServer - OutboundPollingThread");
        this.outboundPollingThread.start();
        while (!this.shutdown) {
            Thread.sleep(1000);
        }
    }

    @Override
    public void run() {
        try {
            loadConfiguration();
            dbsql.start();
            //Service.getInstance().S.SERIAL_NOFLUSH = true;
            Service.getInstance().startService();
            TrayUI.setReadyGateway(true);
            TrayUI.setConnect(true);
            process();
            System.err.println("---ShutDown----");
            dbsql.stop();
            Service.getInstance().stopService();
            TrayUI.setConnect(false);
            if (this.inboundPollingThread != null) {
                this.inboundPollingThread.interrupt();
                this.inboundPollingThread.join();
            }
            if (this.outboundPollingThread != null) {
                this.outboundPollingThread.interrupt();
                this.outboundPollingThread.join();
            }
        } catch (Exception e) {
            LoggerInf.getInstance("iliskiSend").logError("SMSServer error!", e, null);
        }
    }

    private void loadConfiguration() throws GatewayException {
        String device = this.dbsql.getProperty("device");
        //Integer baudRate = Integer.getInteger(device);this.dbsql.getProperty("device");//"/dev/tty.HUAWEIMobile-Modem"
        SerialModemGateway gateway = new SerialModemGateway("modem.iliski",
                device, 115200, "", "");
        // Set the modem protocol to PDU (alternative is TEXT). PDU is the default, anyw
        //<gateway>.getATHandler().setStorageLocations("SM");
        //gateway.getATHandler().setStorageLocations("SM");
        gateway.setSimPin("0000");
        gateway.setProtocol(Protocols.PDU);
        gateway.setInbound(true);
        gateway.setOutbound(true);

        Service.getInstance().addGateway(gateway);
        LoggerInf.getInstance("iliskiSend").logInfo(
                "SMSServer: added gateway " + gateway.getGatewayId() + " / "
                + gateway.getStatus(), null, null);
    }

    class Shutdown extends Thread {

        @Override
        public void run() {
            LoggerInf.getInstance("iliskiSend").logInfo(
                    "serverku shutting down, please wait...", null, null);
            serverku.this.shutdown = true;
            try {
                dbsql.stop();
                if (Service.getInstance().getQueueManager() != null) {
                    Service.getInstance().getQueueManager().removeAllPendingMessages();
                }
                if (Service.getInstance().getQueueManager() != null) {
                    Service.getInstance().getQueueManager().removeAllDelayedMessages();
                }
                Service.getInstance().stopService();
                TrayUI.setConnect(false);
                if (serverku.this.inboundPollingThread != null) {
                    serverku.this.inboundPollingThread.interrupt();
                    serverku.this.inboundPollingThread.join();
                }
                if (serverku.this.outboundPollingThread != null) {
                    serverku.this.outboundPollingThread.interrupt();
                    serverku.this.outboundPollingThread.join();
                }
            } catch (Exception e) {
                LoggerInf.getInstance("iliskiSend").logError("Shutdown hook error.", e, null);
            }
        }
    }

    void readMessages() {
        List<InboundMessage> msgList = new ArrayList<InboundMessage>();
        try {
            Service.getInstance().readMessages(msgList, MessageClasses.ALL);
            if (msgList.size() > 0) {

                dbsql.messagesReceived(msgList);
                int in = 0;
                for (InboundMessage msg : msgList) {
                    // inject fungsi new Toaster bounce
                    Service.getInstance().deleteMessage(msg);
                    JNotifWindow.setKali = in;
                    JNotifWindow.showNotif("Pengirim :: " + msg.getOriginator() + "\n Pesan :: " + msg.getText(), true);
                    in++;
                }
            }
        } catch (Exception e) {
            Logger.getInstance().logError("SMSServer: reading messages exception!", e, null);
        }
        msgList.clear();
    }

    class InboundPollingThread extends Thread {

        @Override
        public void run() {
            try {
                while (!serverku.this.shutdown) {
                    LoggerInf.getInstance("iliskiSend").logDebug(
                            "InboundPollingThread() run.", null, null);
                    readMessages();
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                LoggerInf.getInstance("iliskiSend").logDebug(
                        "InboundPollingThread() interrupted.", null, null);
            } catch (Exception e) {
                LoggerInf.getInstance("iliskiSend").logDebug(
                        "Error in InboundPollingThread()", e, null);
            }
        }
    }

    void sendMessages() {
        boolean foundOutboundGateway = false;
        for (org.smslib.AGateway gtw : Service.getInstance().getGateways()) {
            if (gtw.isOutbound()) {
                foundOutboundGateway = true;
                break;
            }
        }

        if (foundOutboundGateway) {
            List<OutboundMessage> msgList = new ArrayList<OutboundMessage>();

            try {
                msgList.addAll(dbsql.getMessagesToSend());
            } catch (Exception ex) {
                System.err.println(ex.getMessage());
            }

            Logger.getInstance().logInfo("SMSServer: sending synchronously... ", null, null);

            for (int i = 0; i < msgList.size(); i++) {
                try {
                    Service.getInstance().sendMessage(msgList.get(i));
                    dbsql.markMessage(msgList.get(i));
                    System.err.println(dbsql.getIdSMSOut() + " ::<<< kode Sms Tabel");
                } catch (Exception e) {
                    LoggerInf.getInstance("iliskiSend").logError("SMSServer: sending messages exception!", e, null);
                    try {
                        dbsql.markMessage(msgList.get(i));
                    } catch (Exception e1) {
                        LoggerInf.getInstance("iliskiSend").logError("SMSServer: sending messages exception!", e1, null);
                    }
                }
            }
            msgList.clear();
        }
    }

    class OutboundPollingThread extends Thread {

        @Override
        public void run() {
            try {
                while (!serverku.this.shutdown) {
                    LoggerInf.getInstance("iliskiSend").logDebug(
                            "OutboundPollingThread() run.", null, null);
                    sendMessages();
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                LoggerInf.getInstance("iliskiSend").logDebug(
                        "OutboundPollingThread() interrupted.", null, null);
            } catch (Exception e) {
                LoggerInf.getInstance("iliskiSend").logDebug(
                        "Error in OutboundPollingThread()", e, null);
            }
        }
    }

    class InboundNotification implements IInboundMessageNotification {

        @Override
        public void process(org.smslib.AGateway gateway, MessageTypes msgType,
                InboundMessage msg) {
            List<InboundMessage> msgList = new ArrayList<InboundMessage>();
            msgList.add(msg);

            try {
                dbsql.messagesReceived(msgList);
                Service.getInstance().deleteMessage(msg);
                JNotifWindow.showNotif("Pengirim :: " + msg.getOriginator() + "\n Pesan :: " + msg.getText(), true);
                Logger.getInstance().logDebug("InboundNotification run().", null, null);
            } catch (Exception e) {
                Logger.getInstance().logError("Error receiving message!", e, null);
            }
            msgList.clear();
        }
    }

    class OutboundNotification implements IOutboundMessageNotification {

        @Override
        public void process(org.smslib.AGateway gateway,
                org.smslib.OutboundMessage msg) {
            try {
                System.out.println("Outbound handler called from Gateway: "
                        + gateway.getGatewayId());
                System.out.println(msg);
            } catch (Exception e) {
                LoggerInf.getInstance("iliskiSend").logError(
                        "IOutboundMessageNotification error.", e, null);
            }
        }
    }

    class CallNotification implements ICallNotification {

        @Override
        public void process(org.smslib.AGateway gateway, String callerId) {
            try {
//                hdNotif.showNotif("Pengirim :: " + callerId + "\n Pesan :: " + gateway.getGatewayId());
                JNotifWindow.showNotif("Pengirim :: " + callerId + "\n Pesan :: " + gateway.getGatewayId(), true);
            } catch (Exception e) {
                LoggerInf.getInstance("iliskiSend").logError("ICallNotification error.", e,
                        null);
            }
        }
    }

    class QueueSendingNotification implements IQueueSendingNotification {

        @Override
        public void process(org.smslib.AGateway gateway, OutboundMessage msg) {
            LoggerInf.getInstance("iliskiSend").logInfo(
                    "**** >>>> Now Sending: " + msg.getRecipient(), null,
                    gateway.getGatewayId());
        }
    }

    class OrphanedMessageNotification implements IOrphanedMessageNotification {

        @Override
        public boolean process(org.smslib.AGateway gateway, InboundMessage msg) {
            System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
            System.out.println("&&&&&&&&&&&&&&&&& ORPHANED INFO &&&&&&&&&&&&&&&&&");
            System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
            System.out.println(msg);
            System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
            System.out.println("&&&&&&&&&&&&&&&&& ORPHANED INFO &&&&&&&&&&&&&&&&&");
            System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
            // Return FALSE to leave orphaned parts in memory.
            return true;
        }
    }

    class USSDboundNotification implements IUSSDNotification {

        @Override
        public void process(AGateway ag, USSDResponse ussdr) {
            TrayUI.respone.setText(ussdr.getContent());
            //JNotifWindow.showNotif(ussdr.getContent());
        }
    }

    public boolean checkPriorityTimeFrame(int priority) {
        String timeFrame;
        String from, to, current;
        Calendar cal = Calendar.getInstance();
        if (priority < 0) {
            timeFrame = "0000-2359";//getProperties().getProperty("settings.timeframe.low", "0000-2359");
        } else if (priority == 0) {
            timeFrame = "0000-2359";//getProperties().getProperty("settings.timeframe.normal", "0000-2359");
        } else if (priority >= 0) {
            timeFrame = "0000-2359";//getProperties().getProperty("settings.timeframe.high", "0000-2359");
        } else {
            timeFrame = "0000-2359";
        }
        from = timeFrame.substring(0, 4);
        to = timeFrame.substring(5, 9);
        cal.setTime(new java.util.Date());
        current = cal.get(Calendar.HOUR_OF_DAY) < 10 ? "0" + cal.get(Calendar.HOUR_OF_DAY) : "" + cal.get(Calendar.HOUR_OF_DAY);
        current += cal.get(Calendar.MINUTE) < 10 ? "0" + cal.get(Calendar.MINUTE) : "" + cal.get(Calendar.MINUTE);
        if ((Integer.parseInt(current) >= Integer.parseInt(from)) && (Integer.parseInt(current) < Integer.parseInt(to))) {
            return true;
        }
        return false;
    }
}
